package com.samsung.sbackup;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.Toast;

import com.samsung.handler.CalendarHandler;
import com.samsung.handler.ContactHandler;
import com.samsung.handler.SmsHandler;
import com.samsung.handler.ZipHandler;

public class QuickBackup extends Activity {

	Button btnBack, btnBackup;
	LinearLayout lnrContacts, lnrSms, lnrCalendar, lnrApps;
	CheckBox cbContacts, cbSms, cbCalendar, cbApps;
	EditText edPassword;
	Switch swPassword;

	int count = 0;
	ContactHandler contact;
	SmsHandler sms;
	ArrayList<String> list;
	int checkDuplicate;
	SmsThread smsThread;
	ContactThread contactThread;
	CalendarThread calendarThread;
	CalendarHandler calendar;
	ProgressBar pb;
	ProgressDialog progressdialog;
	SharedPreferences sharedPref;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.quick_backup);
		getActionBar().setDisplayHomeAsUpEnabled(true);

		sharedPref = PreferenceManager
				.getDefaultSharedPreferences(getApplicationContext());

		btnBack = (Button) findViewById(R.id.quick_backup_btnBack);
		btnBackup = (Button) findViewById(R.id.quick_backup_btnBackup);
		lnrContacts = (LinearLayout) findViewById(R.id.quick_backup_linearContacts);
		lnrSms = (LinearLayout) findViewById(R.id.quick_backup_linearSms);
		lnrCalendar = (LinearLayout) findViewById(R.id.quick_backup_linearCalendar);
		lnrApps = (LinearLayout) findViewById(R.id.quick_backup_linearApps);
		cbContacts = (CheckBox) findViewById(R.id.quick_backup_cbContacts);
		cbSms = (CheckBox) findViewById(R.id.quick_backup_cbSms);
		cbCalendar = (CheckBox) findViewById(R.id.quick_backup_cbCalendar);
		cbApps = (CheckBox) findViewById(R.id.quick_backup_cbApps);
		edPassword = (EditText) findViewById(R.id.quick_backup_edPassword);
		swPassword = (Switch) findViewById(R.id.quick_backup_swPassword);
		list = new ArrayList<String>();

		edPassword.setEnabled(false);
		edPassword.setFocusable(false);
		edPassword.setFocusableInTouchMode(false);

		swPassword.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(CompoundButton buttonView,
					boolean isChecked) {
				if (isChecked) {
					edPassword.setEnabled(true);
					edPassword.setFocusable(true);
					edPassword.setFocusableInTouchMode(true);
				} else
					edPassword.setEnabled(false);
			}
		});

		lnrContacts.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				cbContacts.setChecked(!cbContacts.isChecked());
			}
		});

		lnrSms.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				cbSms.setChecked(!cbSms.isChecked());
			}
		});

		lnrCalendar.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				cbCalendar.setChecked(!cbCalendar.isChecked());
			}
		});

		lnrApps.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				cbApps.setChecked(!cbApps.isChecked());
			}
		});

		btnBack.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				onBackPressed();
			}
		});

		btnBackup.setOnClickListener(new OnClickListener() {
			SimpleDateFormat sf = new SimpleDateFormat("HH.mm dd-MM-yyyy",
					Locale.getDefault());
			final String folder = sharedPref.getString(
					FragmentSettingsPreference.BACKUP_PATH, "/");
			final int maxBackups = Integer.parseInt(sharedPref.getString(
					FragmentSettingsPreference.MAX_BACKUPS, "5"));

			@Override
			public void onClick(View arg0) {
				File f = new File(folder);
				MainActivity.createFolder(folder, QuickBackup.this);
				if (f.exists()) {
					String date = sf.format(Calendar.getInstance().getTime());
					String currentBackups = "";
					list.clear();
					if (cbContacts.isChecked()) {
						list.add("contact");
						currentBackups += "contact ";
					}
					if (cbSms.isChecked()) {
						list.add("sms");
						currentBackups += "sms ";
					}
					if (cbCalendar.isChecked()) {
						list.add("calendar");
						currentBackups += "calendar";
					}
					if (cbApps.isChecked()) {
						list.add("app");
						currentBackups += "app";
					}

					MaxBackupsChecker(currentBackups, maxBackups, folder);

					if (list.size() != 0) {
						{
							progressdialog = new ProgressDialog(
									QuickBackup.this);
							progressdialog.setTitle("Backing up...");
							progressdialog
									.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
							progressdialog.setIndeterminate(false);
							progressdialog.setCancelable(false);
							progressdialog.show();
							for (int i = 0; i < list.size(); i++) {

								if (list.get(i).equals("calendar")) {
									for (File s : f.listFiles()) {
										if (s.getName().equals(
												"calendar_" + date + ".zip")) {
											s.delete();
										}
									}

									calendar = new CalendarHandler(
											QuickBackup.this);
									CalendarTask s3 = new CalendarTask();
									s3.execute(list.get(list.size() - 1));
									calendarThread = new CalendarThread(date);
									calendarThread.start();

								} else if (list.get(i).equals("contact")) {
									for (File s : f.listFiles()) {
										if (s.getName().equals(
												"contact_" + date + ".zip")) {
											s.delete();
										}

									}

									contact = new ContactHandler(
											QuickBackup.this);
									ContactTask s1 = new ContactTask();
									s1.execute(list.get(list.size() - 1));

									contactThread = new ContactThread(date);
									contactThread.start();
									Log.e("", "contact");

								} else if (list.get(i).equals("sms")) {
									for (File s : f.listFiles()) {
										if (s.getName().equals(
												"sms" + date + ".zip")) {
											s.delete();
										}

									}

									sms = new SmsHandler(QuickBackup.this);
									SMSTask s2 = new SMSTask();
									s2.execute(list.get(list.size() - 1));
									smsThread = new SmsThread(date);
									smsThread.start();
									Log.e("", "sms");

								} else if (list.get(i).equals("app")) {
									if (i == 0)
										new BackupApps().execute();
								}
							}
							count = 0;
						}
					}
				} else {
					Toast.makeText(
							QuickBackup.this,
							"Backup folder doesn't exist, please reset in Settings",
							Toast.LENGTH_LONG).show();
				}
			}
		});
	}

	private class ContactTask extends AsyncTask<String, Integer, String> {

		@Override
		protected void onPreExecute() {

			progressdialog.setMax(contact.phones.getCount());
			super.onPreExecute();
		}

		@Override
		protected String doInBackground(String... params) {

			while (contact.progress < contact.phones.getCount()
					&& !contact.isError()) {
				if (checkDuplicate != contact.progress) {
					checkDuplicate = contact.progress;
					progressdialog.setProgress(contact.progress);
				}
			}
			if (params[0].equals("contact"))
				return "contact";
			return "";
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
		}

		@Override
		protected void onPostExecute(String result) {
			if (contact.isError())
				Toast.makeText(QuickBackup.this, contact.getErrorMessage(),
						Toast.LENGTH_LONG).show();
			else if (contact.phones.getCount() > 0)
				Toast.makeText(QuickBackup.this, "Done backing up contacts",
						Toast.LENGTH_SHORT).show();
			else
				Toast.makeText(QuickBackup.this, "No contacts found",
						Toast.LENGTH_SHORT).show();
			if (result.equals("contact"))
				progressdialog.dismiss();
			if (list.contains("app")
					&& !(list.contains("calendar") || list.contains("sms")))
				new BackupApps().execute();
		}
	}

	private class SMSTask extends AsyncTask<String, Integer, String> {
		String first = list.get(0);

		@Override
		protected void onPreExecute() {

			Log.e("list(0)", list.get(0));
			if ((first.equals("sms"))) {
				progressdialog.setMax(sms.c.getCount());
			}
			super.onPreExecute();

		}

		@Override
		protected String doInBackground(String... params) {
			if (first.equals("contact")) {
				progressdialog.setMax(sms.c.getCount());

			}
			while (sms.progress < sms.c.getCount() && !sms.isError()) {
				if (checkDuplicate != sms.progress) {
					checkDuplicate = sms.progress;
					progressdialog.setProgress(sms.progress);
				}
			}
			if (params[0].equals("sms"))
				return "sms";

			return "";
		}

		@Override
		protected void onPostExecute(String result) {
			if (sms.isError())
				Toast.makeText(QuickBackup.this, sms.getErrorMessage(),
						Toast.LENGTH_LONG).show();
			else if (sms.c.getCount() != 0)
				Toast.makeText(QuickBackup.this, "Done backing up sms",
						Toast.LENGTH_SHORT).show();
			else
				Toast.makeText(QuickBackup.this, "No sms found",
						Toast.LENGTH_SHORT).show();
			if (result.equals("sms"))
				progressdialog.dismiss();
			if (list.contains("app") && !(list.contains("calendar")))
				new BackupApps().execute();
		}
	}

	private class CalendarTask extends AsyncTask<String, Integer, String> {
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}

		@Override
		protected String doInBackground(String... params) {
			progressdialog.setMax(calendar.totalRecord);

			while (calendar.progress < calendar.totalRecord
					&& !calendar.isError()) {
				if (checkDuplicate != calendar.progress) {
					checkDuplicate = calendar.progress;
					progressdialog.setProgress(calendar.progress);
				}
			}
			if (params[0].equals("calendar"))
				return "calendar";

			return "";
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
		}

		@Override
		protected void onPostExecute(String result) {
			if (calendar.isError())
				Toast.makeText(QuickBackup.this, calendar.getErrorMessage(),
						Toast.LENGTH_LONG).show();
			else if (calendar.totalRecord > 0)
				Toast.makeText(QuickBackup.this, "Done backing up calendar",
						Toast.LENGTH_SHORT).show();
			else
				Toast.makeText(QuickBackup.this, "No events found",
						Toast.LENGTH_SHORT).show();
			if (result.equals("calendar"))
				progressdialog.dismiss();
			if (list.contains("app"))
				new BackupApps().execute();
		}
	}

	public class ContactThread extends Thread {
		public ContactThread(String str) {
			contact.setFile(sharedPref.getString(
					FragmentSettingsPreference.BACKUP_PATH, "/")
					+ "/contact_"
					+ str + ".vcf");
		}

		@Override
		public void run() {
			if (contact.phones.getCount() > 0) {
				contact.backup();
				if (swPassword.isChecked()
						&& !edPassword.getText().toString().isEmpty()) {
					ZipHandler.zipCompress(
							contact.getFile().substring(0,
									contact.getFile().lastIndexOf("/")),
							contact.getFile(), edPassword.getText().toString());
				} else
					ZipHandler.zipCompress(
							contact.getFile().substring(0,
									contact.getFile().lastIndexOf("/")),
							contact.getFile(), null);

				File f = new File(contact.getFile());
				f.delete();
			}
		}
	}

	public class SmsThread extends Thread {
		public SmsThread(String str) {
			sms.setFile(sharedPref.getString(
					FragmentSettingsPreference.BACKUP_PATH, "/")
					+ "/sms_"
					+ str + ".xml");
		}

		@Override
		public void run() {
			{
				try {
					if (contactThread != null)
						contactThread.join();
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (sms.c.getCount() > 0) {
					sms.backup(getContentResolver());

					if (swPassword.isChecked()
							&& !edPassword.getText().toString().isEmpty()) {
						ZipHandler.zipCompress(
								sms.getFile().substring(0,
										sms.getFile().lastIndexOf("/")),
								sms.getFile(), edPassword.getText().toString());
					} else
						ZipHandler.zipCompress(
								sms.getFile().substring(0,
										sms.getFile().lastIndexOf("/")),
								sms.getFile(), null);

					File f = new File(sms.getFile());
					f.delete();
				}
			}
		}
	}

	public class CalendarThread extends Thread {
		public CalendarThread(String str) {
			calendar.setFile(sharedPref.getString(
					FragmentSettingsPreference.BACKUP_PATH, "/")
					+ "/calendar_"
					+ str + ".xml");
		}

		@Override
		public void run() {
			try {
				if (contactThread != null)
					contactThread.join();
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				if (smsThread != null)
					smsThread.join();
			} catch (Exception e) {
				e.printStackTrace();
			}

			if (calendar.totalRecord > 0) {
				calendar.backup();
				if (swPassword.isChecked()
						&& !edPassword.getText().toString().isEmpty()) {
					ZipHandler
							.zipCompress(
									calendar.getFile()
											.substring(
													0,
													calendar.getFile()
															.lastIndexOf("/")),
									calendar.getFile(), edPassword.getText()
											.toString());
				} else
					ZipHandler.zipCompress(
							calendar.getFile().substring(0,
									calendar.getFile().lastIndexOf("/")),
							calendar.getFile(), null);
				File f = new File(calendar.getFile());
				f.delete();
			}
		}
	}

	public class BackupApps extends AsyncTask<Void, Integer, String> {
		ProgressDialog progressDialog;
		ArrayList<ApplicationInfo> appsList;
		boolean isError;
		String errorMessage;

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			isError = false;
			errorMessage = "No errors";
			// get all application infos
			ArrayList<ApplicationInfo> infos = (ArrayList<ApplicationInfo>) getPackageManager()
					.getInstalledApplications(PackageManager.GET_META_DATA);
			appsList = new ArrayList<ApplicationInfo>();
			for (ApplicationInfo applicationInfo : infos) {
				if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)
					appsList.add(applicationInfo);
			}
			progressDialog = new ProgressDialog(QuickBackup.this);
			progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			progressDialog.setMax(appsList.size());
			progressDialog.setTitle("Backing up...");
			progressDialog.setCancelable(false);
			if (appsList.size() != 0)
				progressDialog.show();
		}

		@Override
		protected String doInBackground(Void... params) {
			int count = 0;
			for (ApplicationInfo item : appsList) {
				try {
					File f1 = new File(item.publicSourceDir);

					String path = sharedPref.getString(
							FragmentSettingsPreference.BACKUP_PATH, "/");

					File f2 = new File(path + "/" + "app");
					f2.mkdirs();
					f2 = new File(f2.getPath() + "/"
							+ item.loadLabel(getPackageManager()) + ".apk");
					f2.createNewFile();
					InputStream in = new FileInputStream(f1);

					OutputStream out = new FileOutputStream(f2);

					byte[] buf = new byte[1024];
					int len;
					while ((len = in.read(buf)) > 0) {
						out.write(buf, 0, len);
					}
					in.close();
					out.close();
					System.out.println("File copied.");
				} catch (FileNotFoundException ex) {
					ex.printStackTrace();
					isError = true;
					errorMessage = "Error" + ex.toString();
				} catch (IOException e) {
					e.printStackTrace();
					isError = true;
					errorMessage = "Error" + e.toString();
				}
				count++;
				publishProgress(count);
			}

			if (appsList.size() != 0)
				return "Done backing up applications";
			else
				return "There is no application installed";
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
			progressDialog.setProgress(values[0]);
		}

		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			progressdialog.dismiss();
			progressDialog.dismiss();
			if (isError)
				Toast.makeText(QuickBackup.this, errorMessage,
						Toast.LENGTH_SHORT).show();
			else
				Toast.makeText(QuickBackup.this, result, Toast.LENGTH_SHORT)
						.show();
		}
	}

	/**
	 * check the max backups condition and delete files before backing up
	 * 
	 * @param currentBackups
	 *            Number of files will be backing up right after
	 * @param maxBackups
	 *            Max number of files are allowed
	 * @param backupPath
	 *            current backup path
	 */
	public static void MaxBackupsChecker(String currentBackups, int maxBackups,
			String backupPath) {
		ArrayList<File> sms = new ArrayList<File>();
		ArrayList<File> contact = new ArrayList<File>();
		ArrayList<File> calendar = new ArrayList<File>();

		File f = new File(backupPath);
		if (f.list() != null) {
			for (File file : f.listFiles()) {
				if (file.getName().contains("sms"))
					sms.add(file);
				if (file.getName().contains("contact"))
					contact.add(file);
				if (file.getName().contains("calendar"))
					calendar.add(file);
			}

			// sort files
			Collections.sort(sms, new LastBackupsComparator());
			Collections.sort(contact, new LastBackupsComparator());
			Collections.sort(calendar, new LastBackupsComparator());

			int needDeletedFiles = 0;

			// check and delete sms
			needDeletedFiles = sms.size() - maxBackups;
			if (currentBackups.contains("sms"))
				needDeletedFiles += 1;

			if (needDeletedFiles == 1)
				sms.get(0).delete();
			else
				for (int i = 0; i < needDeletedFiles; i++) {
					sms.get(i).delete();
				}

			// check and delete contact
			needDeletedFiles = contact.size() - maxBackups;
			if (currentBackups.contains("contact"))
				needDeletedFiles += 1;

			if (needDeletedFiles == 1)
				contact.get(0).delete();
			else
				for (int i = 0; i < needDeletedFiles; i++) {
					contact.get(i).delete();
				}

			// check and delete calendar
			needDeletedFiles = calendar.size() - maxBackups;
			if (currentBackups.contains("calendar"))
				needDeletedFiles += 1;

			if (needDeletedFiles == 1)
				calendar.get(0).delete();
			else
				for (int i = 0; i < needDeletedFiles; i++) {
					calendar.get(i).delete();
				}
		}
	}

	public static class LastBackupsComparator implements Comparator<File> {

		@Override
		public int compare(File one, File another) {
			int returnValue = 0;
			if (one.lastModified() < another.lastModified())
				returnValue = -1;
			else if (one.lastModified() == another.lastModified())
				returnValue = 0;
			else if (one.lastModified() > another.lastModified())
				returnValue = 1;
			return returnValue;
		}
	}

	public static class NameComparator implements Comparator<File> {
		@Override
		public int compare(File one, File another) {
			return one.getName().compareTo(another.getName());
		}
	}
	
}
